using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

public class R
{
    #region Statics
    static R()
    {
        Dummy = nouse;
        for (i1 = Dummy.Method.GetParameters().Length - 1; i1 >= 0; i1--)
        {
            for (i2 = Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes().Length - 1; i2 >= 0; i2--)
            {
                string name = Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2].FullName;
                dict1[name] = Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2];
                dict1[name] = i1;
                dict2[name] = i2;
            }
        }
    }
    static object[] empty = new object[0];
    static readonly NoUse Dummy;
    static readonly int ModulesCount;
    static object nouse(object obj, BitArray ba)
    {
        return null;
    }
    delegate object NoUse(object obj, BitArray ba);

    static Dictionary<string, object> dict = new Dictionary<string, object>();
    static Dictionary<string, int> dict1 = new Dictionary<string, int>(), dict2 = new Dictionary<string, int>();
    public static void GetII(string typename, out int i1, out int i2)
    {
        if (!dict1.TryGetValue(typename, out i1) || !dict2.TryGetValue(typename, out i2))
            throw new InvalidProgramException();
    }
    public static string TypeNameOf(object obj)
    {
        if (obj == null)
            return null;
        return (string)Dummy.Method.ReturnType.GetProperty("FullName").GetGetMethod().Invoke(
            Dummy.Method.ReturnType.GetMethod("GetType").Invoke(obj, empty), empty);
    }
    public static object GetT(string typename)
    {
        return dict[typename];
    }
    public static bool IsA(object obj, string typename)
    {
        if (obj == null)
            return true;
        int i1, i2, j1, j2;
        GetII(typename, out i1, out i2);
        GetII("System.Type", out j1, out j2);
        return (bool)Dummy.Method.GetParameters()[j1].ParameterType.Module.GetTypes()[j2].GetMethod("IsAssignableFrom").Invoke(
            Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2], new object[]{
                Dummy.Method.ReturnType.GetMethod("GetType").Invoke(obj, empty)
            }
            );
    }
    #endregion
    public R(object obj)
    {
        if (obj == null)
        {
            throw new InvalidProgramException();
        }
        this.V = obj;
        this.T = TypeNameOf(obj);
    }
    public R(object obj, string typename)
    {
        if (!IsA(obj, typename))
        {
            throw new InvalidProgramException();
        }
        this.V = obj;
        this.T = typename;
    }
    public readonly obj V;
    public readonly string T;
    public static R C(string typename, params object[] pms)
    {
        int i1, i2;
        GetII(typename, out i1, out i2);
        return new R(Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2].GetConstructor().Invoke(V, pms);
    }
    public object M(string methodname, params object[] pms)
    {
        int i1, i2;
        GetII(T, out i1, out i2);
        return Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2].GetMethod(methodname).Invoke(V, pms);
    }
    public object M(string methodname, params R[] pms)
    {
        object[] objs = new object[pms.Length];
        for (int i = 0; i < objs.Length; i++)
        {
            if (pms[i] != null)
            {
                objs[i] = pms[i].V;
            }
        }
        return M(methodname, objs);
    }
    public object CC(string methodname, params object[] pms)
    {
        R[] rs = new R[pms.Length];
        for (int i = 0; i < objs.Length; i++)
        {
            if (pms[i] != null)
            {
                rs[i] = new R(pms[i]);
            }
        }
    }
    public object CC(string methodname, params R[] pms)
    {
        return CC(methodname, objs);
    }
    public object this[string propertyname]
    {
        get {
            int i1, i2;
            GetII(T, out i1, out i2);
            return Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2].GetProperty(methodname).GetGetMethod().Invoke(V,empty);
        }
        set
        {
            int i1, i2;
            GetII(T, out i1, out i2);
            return Dummy.Method.GetParameters()[i1].ParameterType.Module.GetTypes()[i2].GetProperty(methodname).GetSetMethod().Invoke(V, new object[] { value });
        }
    }
}
